package src;

import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.Point;
import java.util.ArrayList;
import javax.swing.JPanel;  
import javax.swing.JTabbedPane;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author JMix
 */
class JPanelDibujo extends JPanel implements MouseListener, MouseMotionListener, Printable {
    
    private static final int bordeSuperior = 80;
    private static final int bordeIzquierdo = 75;
    private static final int constanteTrimestre = 30;
    private static final int constanteSemestre = 40;
    public static final int vertical = 0;
    public static final int horizontal = 1;
    private final int maxCursos = 20;
    
    private final int constanteEnX = 50;
    private final int constanteEnY = 40;
    
    private int identificador;
    private Memoria memoria;
    private int niveles = 0;
    ArrayList<JFigura> figures;
    //ArrayList<JFlecha> flechas;
    //private ArrayList<PrototipoFlecha> flechas;
    Curso[][] cursos;
    JFigura figuraPresionada;
    Point posicionFiguraPresionada;
    private JVentana ventana;
    private int orientacion;
    private Seleccionador seleccionador;
    private JPopupMenuJPanelDibujo popupMenu;
    private String nombreMalla;
    Flecha flechaPresionada;
    Flecha ultimaFlechaPresionada;
    JTabbedPane jtabbedpane;
    
    public JPanelDibujo(JTabbedPane jtabbedpane){
        super.addMouseListener(this);
        super.addMouseMotionListener(this);
        super.setLayout(null);
        this.memoria = new Memoria();
        this.figures = new ArrayList();
        //this.flechas = new ArrayList();
        this.ventana = null;
        this.memoria.addMemento(new Memento(figures));
        this.seleccionador = new Seleccionador();
        this.popupMenu = new JPopupMenuJPanelDibujo();
        this.nombreMalla = "NuevaMalla";
        this.orientacion = vertical;
        this.ultimaFlechaPresionada = null;
        this.jtabbedpane = jtabbedpane;
    }
    
    @Override
    public void paint(Graphics g){
        super.paint(g);
        //super.updateUI();
        Graphics2D g2d= (Graphics2D) g;
        // Necesario para el antialiasing
        g2d.addRenderingHints( new RenderingHints( RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON ) ); 
        this.pintarEtiquetaMalla(g2d);
        this.pintarEtiquetasNiveles(g2d);
        this.revisarFlechas();
        this.pintarFlechas(g2d);
        if( figuraPresionada != null )
            this.seleccionador.paint(g);
    }
    
    private void pintarEtiquetaMalla( Graphics2D g2d ){
        g2d.setFont(new Font("Arial", 0, 18));
        g2d.setColor( Color.BLACK );
        if( orientacion == vertical )
        {
            int x = super.getWidth();
            g2d.drawString( this.nombreMalla , x/2 - nombreMalla.length()*5, 50 );
        }
        else if( orientacion == horizontal )
        {
            int y = super.getHeight()/2 - nombreMalla.length()*13;
            for( int i = 0 ; i < nombreMalla.length() ; i++ )
            {
                String letra = nombreMalla.charAt(i) + "";
                g2d.drawString( letra , 25 , y + i*25 );
            }
        }
    }
    
    private void pintarEtiquetasNiveles(Graphics2D g2d){
        g2d.setFont(new Font("Arial", 0, 14));
        g2d.setColor( Color.BLACK );
        String etiqueta = "Año ";
        if (this.orientacion == vertical){
            for (int i=0; i<this.niveles; i++){
                g2d.drawString(etiqueta +(i+1), 45, (i)*170 + (i+2)*30 - i*10 );
            }
        }
        else if (this.orientacion == horizontal){
            for (int i=0; i<this.niveles; i++){
                g2d.drawString(etiqueta +(i+1), (i)*175 + 75 + (i+1)*15, 50);
            }
        }
    }
    
     private void pintarFlechas(Graphics2D g2d) {
         for (JFigura fig : this.figures)
             fig.pintarLineasHorizontales(g2d);
         for (JFigura fig : this.figures)
             fig.pintarLineasVerticales(g2d);
         for (JFigura fig : this.figures)
             fig.pintarPuntas(g2d);
         
    }
     
    public void addJFigura(JFigura fig){
        this.figures.add(fig);
        super.add(fig);
        super.updateUI();
    }
    
    @Override
    public void mouseClicked( MouseEvent arg0 ) {
        //figuraPresionada= buscarFigura(arg0.getPoint()); // busca si el click esta dentro de un cuadrado
        int clicks = arg0.getClickCount();
        switch (clicks){
            case 1:
                imprimirInfo(this.figuraPresionada);
                imprimirInfo(this.ultimaFlechaPresionada);
                this.resaltarFlechas(this.figuraPresionada);
                break;
                
            case 2:
                if (this.figuraPresionada != null){
                    this.ventana.vistaDatosRamo.setAgregar(false);
                    String nombre = figuraPresionada.getNombre();
                    int nivel = figuraPresionada.getNivel();
                    //System.out.println("Figura: "+ nombre + " nivel: " + nivel );
                    this.ventana.mostrarVistaDatosRamo(nivel, nombre);
                    
                }
                break;
        }
    }
    
    @Override
    public void mousePressed( MouseEvent arg0 ) {
        int boton = arg0.getButton();
        Point punto = arg0.getPoint();
        String elementoClickeado = buscarElementoClickeado(punto);
        
        this.flechaPresionada = this.buscarFlecha(punto);     
        this.figuraPresionada = this.buscarFigura(punto);
        if( figuraPresionada != null )
            this.posicionFiguraPresionada = figuraPresionada.getPunto();
//        if (flechaPresionada != null)
//            System.out.println("puntos: " + flechaPresionada.seleccionado1 + " y " + flechaPresionada.seleccionado2);
        
        if (boton == 1){
            switch(elementoClickeado){
                case "figura":
                    this.ultimaFlechaPresionada = this.buscarFlecha(figuraPresionada.getRamo());
                    this.traerFiguraAlFrente(this.figuraPresionada);
                    //Definimos distancia extra al centro en que es movida la figura
                    figuraPresionada.setDragFromX( punto.x - figuraPresionada.getX() );
                    figuraPresionada.setDragFromY( punto.y - figuraPresionada.getY() );
                    this.seleccionador.setFig( figuraPresionada );  // hay figura seleccionada
                    this.seleccionador.setMostrado(true);
                    super.setCursor(new Cursor(Cursor.MOVE_CURSOR));
                    break;
                case "flecha":
                    this.ultimaFlechaPresionada = this.flechaPresionada;
                    super.setCursor(new Cursor(Cursor.MOVE_CURSOR));
                    break;
                case "espacio vacio":
                    //this.seleccionarFigura(null);
                    this.figuraPresionada = null;
                    this.flechaPresionada = null;
                    this.posicionFiguraPresionada = null;
                    this.seleccionador.setMostrado(false);
                    break;
            }
        }
        
        if (boton == 3){
            System.out.println("click derecho sobre " + elementoClickeado);
            this.popupMenu.show(arg0.getComponent(), punto.x, punto.y, elementoClickeado);
            //seleccionarFigura(null);
        }
        
        super.repaint();
    }

    @Override
    public void mouseReleased( MouseEvent arg0 ) throws NullPointerException
    {
        if( figuraPresionada != null && posicionFiguraPresionada != null )
            if( figuraPresionada.getX() != posicionFiguraPresionada.getX() || figuraPresionada.getY() != posicionFiguraPresionada.getY() )
                centrarFiguraPresionada();
        super.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
        updateUI();
    }

    @Override
    public void mouseEntered( MouseEvent arg0 ) {
    }

    @Override
    public void mouseExited( MouseEvent arg0 ) {
    }
    
    @Override
    public void mouseDragged( MouseEvent arg0 ) {
        if (flechaPresionada != null){
            JFigura figReferencia = this.buscarJFigura(flechaPresionada);
            //System.out.println("FIGURA RELACIONADA: " + figReferencia.getNombre());
            switch(orientacion){
                case vertical:
                    if (flechaPresionada.orientacionTramoSeleccionado() == horizontal){ // movimiento de tramo horizontal
                        flechaPresionada.setPointYTramoSeleccionado(arg0.getY());
                    }
                    else{ // movimiento de tramo vertical
                        if (figReferencia == null){
                            flechaPresionada.setPointXTramoSeleccionado(arg0.getX());
                        }
                        else if (arg0.getX() >= figReferencia.getX() && arg0.getX() <= figReferencia.getX()+figReferencia.getDimension().width){
                            flechaPresionada.setPointXTramoSeleccionado(arg0.getX());
                        }
                    }
                    break;

                case horizontal:
                    if (flechaPresionada.orientacionTramoSeleccionado() == horizontal){ // movimiento de tramo horizontal
                        if (figReferencia == null){
                            flechaPresionada.setPointYTramoSeleccionado(arg0.getY());
                        }
                        else if (arg0.getY() >= figReferencia.getY() && arg0.getY() <= figReferencia.getY()+figReferencia.getAlto()){
                            flechaPresionada.setPointYTramoSeleccionado(arg0.getY());
                        }
                    }
                    else{ // movimiento de tramo vertical
                            flechaPresionada.setPointXTramoSeleccionado(arg0.getX());
                        }
                    break;
            }
        }
        
        else if (figuraPresionada != null){
            figuraPresionada.setFlechasSalientes(orientacion);
            this.setFlechasEntrantes(this.figuraPresionada.getRamo(), orientacion);
            if( orientacion == vertical ){
                figuraPresionada.setX(arg0.getX() - figuraPresionada.getDragFromX());
                figuraPresionada.setBounds(arg0.getX() - figuraPresionada.getDragFromX(), figuraPresionada.getY(),
                                        figuraPresionada.getDimension().width, figuraPresionada.getDimension().height);
                //No salga por los lados - tampoco antes de las etiquetas de cursos
                figuraPresionada.setBounds( Math.max(figuraPresionada.getX(), 50), figuraPresionada.getY(),
                                        figuraPresionada.getDimension().width, figuraPresionada.getDimension().height);
                figuraPresionada.setBounds( Math.min(figuraPresionada.getX(), this.getWidth() - figuraPresionada.getDimension().width),
                                figuraPresionada.getY(), figuraPresionada.getDimension().width, figuraPresionada.getDimension().height );
            }
            else if( orientacion == horizontal ){
                figuraPresionada.setY(arg0.getY() - figuraPresionada.getDragFromY());
                figuraPresionada.setBounds(figuraPresionada.getX(), arg0.getY() - figuraPresionada.getDragFromY(), 
                                            figuraPresionada.getDimension().width, figuraPresionada.getDimension().height);
                //No salga por top ni por bot - tampoco sobre de las etiquetas de cursos
                figuraPresionada.setBounds(figuraPresionada.getX(), Math.max(figuraPresionada.getY(), 50),
                                            figuraPresionada.getDimension().width, figuraPresionada.getDimension().height  );
                figuraPresionada.setBounds(figuraPresionada.getX(), Math.min(figuraPresionada.getY(), this.getHeight() - figuraPresionada.getDimension().height),
                                            figuraPresionada.getDimension().width, figuraPresionada.getDimension().height );
            }
        }
        verificarPosicion();
        super.repaint();
    }

    @Override
    public void mouseMoved( MouseEvent arg0 ) {
    }

    private JFigura buscarFigura( Point point ) {
        for(JFigura f : figures){
            if(f.inside(point)){
                return f;
            }
        }
        return null;
    }
    
    /**
     * Añade JFigura al arraylist de jfiguras
     * @param f 
     */
    public void addFigure(JFigura f) {
        this.figures.add(f);
    }
    
    public void eliminarJFIgura(JFigura fig){
        JFigura eliminar = null;
        //Libera posicion de la figura en la matriz
        for (JFigura f : this.figures){
            if (f == fig){
                eliminar = f;
            }
        }
        if( eliminar != null )
        {
            Ramo aEliminar = eliminar.getRamo();
            ArrayList<Ramo> requisitos = aEliminar.getPreRequisitos();
            System.out.println("se eliminara la figura " + fig.getNombre());
            for (Ramo r : requisitos){
                System.out.println("requisitos " + r.nombre);
                JFigura figura = this.buscarJFigura(r.getNombre(), r.getNivel());
                System.out.println("a eliminar= " + aEliminar.nombre);
                figura.eliminarFlecha(aEliminar);
            }
            this.liberarPosicion();
            super.remove(eliminar);
            this.figures.remove(eliminar);
            this.seleccionador.setMostrado(false);
            super.updateUI();
        }
    }
    
    public boolean existeNombre(String nombre){
        for (JFigura figura : this.figures){
            if (figura.getNombre().equals(nombre))
                return true;
        }
        return false;
    }
    
    public void setVentana(JVentana frame){
        this.ventana = frame;
        this.popupMenu.setVentana(frame);
        System.out.println("ventana seteada");
    }

    public void ingresarRamo(Ramo ramo){
        //Este boolean funciona a la hora de agregar ramos en orientacion horizontal.
        //Cambia la orientacion a vertical, lo agrega normalmente y luego vuelve a horizontal.
        boolean modificarOrientacion = false;
        if( orientacion == horizontal )
        {
            modificarOrientacion = true;
            cambiarOrientacion();
        }
        int nivel = ramo.getNivel();
        String nombre = ramo.getNombre();
        JFigura fig = null;
        Point p = definePosicion( nivel, ramo.getPeriodo() ); //-> retornara posicion lista... eliminar lo siguiente
        //Definir posicion
        fig = new JFigura( (int)p.getX(), (int)p.getY(), nombre, ramo, orientacion);
        fig.defineTamaño(orientacion);
        if (ramo.cantPreRequisitos() > 0){
            this.agregarFlechas(fig);
        }
        //fig.updateUI();
        this.addFigure(fig);
        super.add(fig);
        if( modificarOrientacion )
            cambiarOrientacion();
        this.seleccionador.setFig(fig);
        this.figuraPresionada = fig;
        this.seleccionador.setMostrado(true);
        //this.memoria.addMemento(new Memento(figures));
        this.agregarMemoria();
        if( super.getWidth() < fig.getX() )
            super.setSize(fig.getX() + 2*fig.getAncho() , super.getHeight());
        if( super.getHeight() < fig.getY() )
            super.setSize(super.getWidth() , fig.getY() + 2*fig.getAlto());
        super.updateUI();
        this.seleccionador.repaint();
    }
   
    /**
     * Busca posicion libre en la matriz de espacios, según nivel
     * Por el moemento solo define posicion para una orientacion vertical
     * @param nivel
     * @return Point
     */
    private Point definePosicion(int nivel, String tipo) //Tipo debe ser periodo
    {
        int enNivel = nivel -1;
        Point p = null;
        int j = 0;
        //Buscar posicion
        if( tipo.equals("Anual") || tipo.equals("Trimestre 1") || tipo.equals("Semestre 1") )
        {
            //Revisa todos los puntos del nivel
            for( int i = 0 ; i < cursos[enNivel].length ; i++ )
            {
                Point punto = cursos[enNivel][i].getPunto(); //getPosicion(0) en caso de que se pudiera cambiar
                String t = cursos[enNivel][i].getPeriodo();
                boolean asignar = true;
                for( JFigura f : figures )
                {
                    if( punto.getX() == f.getPunto().getX() && punto.getY() == f.getPunto().getY()) //Punto ocupado si es igual a alguno de cualquier figura
                    {   
                        asignar = false;
                        break;
                    }
                }
                //Asignar indicaria que la posicion no esta ocupada 
                if( asignar && ( t == null || t.equals(quitarNumero(tipo)) ) )
                {
                    cursos[enNivel][i].setPeriodo(quitarNumero(tipo));
                    return punto;
                }
            }
        }
        //Sino: 1)Para semestre 2 puede haber un semestre 1 antes o un espacio vacio, pero si esta el semestre 
        int n = this.getNumeroString(tipo) -1;//Para pedir posicion n-1 del arreglo que las contiene
        for( int i = 0 ; i < cursos[enNivel].length ; i++ )
        {
            Point punto = null;
            if( quitarNumero(tipo).equals( "Trimestre" ) )
                punto = cursos[enNivel][i].getTrimestre(n);
            else if( quitarNumero(tipo).equals( "Semestre" ) )
                punto = cursos[enNivel][i].getSemestre(1);
            String t = cursos[enNivel][i].getPeriodo();
            boolean asignar = true;
            for( JFigura f : figures )
            {
                if( punto.getX() == f.getPunto().getX() && punto.getY() == f.getPunto().getY()) //Punto ocupado si es igual a alguno de cualquier figura
                {   
                    asignar = false;
                    break;
                }
            }
            //Asignar indicaria que la posicion no esta ocupada 
            if( asignar && (t == null || t.equals(quitarNumero(tipo)) ) )
            {
                cursos[enNivel][i].setPeriodo(quitarNumero(tipo));
                return punto;
            }
        }        
        //Algun error
        return null;
    }
    
    /**
     * Esta función revisa si es necesario resetear la posición donde se encuentra la figura.
     * En caso de ser de tipo o período 'Anual' se libera inmediatamene la posicion.
     * En caso de que la figura sea un trimestre o semestre, la posición sólo se libera si los demás lugares
     * que ocupa esa posición en particular están libres, sino la posición de la matriz cursos mantiene su tipo.
     * 
     */
    private void liberarPosicion()
    {
        boolean modificarOrientacion = false;
        if( orientacion == horizontal )
        {
            modificarOrientacion = true;
            cambiarOrientacion();
        }
        Point buscado = posicionFiguraPresionada;
        Point posicion = null;
        String tipo = figuraPresionada.getRamo().getPeriodo();
        int i=0,j=0;
        for( ; i < cursos.length ; i ++ )
        {
            for( ; j < cursos[i].length ; j++ )
            {
                if( tipo.equals("Anual") )
                {
                    posicion = cursos[i][j].getPunto();
                    if( buscado.getX() == posicion.getX() && buscado.getY() == posicion.getY() )
                    {
                        cursos[i][j].quitarPeriodo();
                        return;
                    }
                }
                else if( quitarNumero(tipo).equals("Semestre") )
                {
                    int n = this.getNumeroString(tipo) -1;
                    posicion = cursos[i][j].getSemestre(n);
                    if( buscado.getX() == posicion.getX() && buscado.getY() == posicion.getY() )
                    {
                        if( n == 0 )
                        {
                            Point p2 = cursos[i][j].getSemestre(n +1);
                            if( !tieneFigura(p2) )
                                cursos[i][j].quitarPeriodo();
                            return;
                        }
                        else if( n == 1 )
                        {
                            Point p2 = cursos[i][j].getSemestre(n -1);
                            if( !tieneFigura(p2) )
                                cursos[i][j].quitarPeriodo();
                            return;
                        }
                        else
                            System.out.println("Error!!");
                    }
                }
                else if( quitarNumero(tipo).equals("Trimestre") )
                {
                    int n = this.getNumeroString(tipo) -1;
                    posicion = cursos[i][j].getTrimestre(n);
                    if( buscado.getX() == posicion.getX() && buscado.getY() == posicion.getY() )
                    {
                        if( n == 0 )
                        {
                            Point p2 = cursos[i][j].getTrimestre(n +1);
                            Point p3 = cursos[i][j].getTrimestre(n +2);
                            if( !tieneFigura(p2) && !tieneFigura(p3) )
                                cursos[i][j].quitarPeriodo();
                            return;
                        }
                        else if( n == 1 )
                        {
                            Point p2 = cursos[i][j].getTrimestre(n -1);
                            Point p3 = cursos[i][j].getTrimestre(n +1);
                            if( !tieneFigura(p2) && !tieneFigura(p3) )
                                cursos[i][j].quitarPeriodo();
                            return;
                        }
                        else if( n == 2 )
                        {
                            Point p2 = cursos[i][j].getTrimestre(n -1);
                            Point p3 = cursos[i][j].getTrimestre(n -2);
                            if( !tieneFigura(p2) && !tieneFigura(p3) )
                                cursos[i][j].quitarPeriodo();
                            return;
                        }
                        else
                            System.out.println("Error!!");
                    }
                    break;
                }
            }
        }
        if( modificarOrientacion )
            cambiarOrientacion();
    }
    
    private boolean tieneFigura( Point punto )
    {
        for( JFigura f : figures )
        {
            if( f != null )
                if( f.getX() == punto.getX() && f.getY() == punto.getY() )
                    return true;
        }
        return false;
    }
    
    /**
     * Verifica que la posicion hasta donde ha sido arrastrada la JFigura, sea "apta" para el posicionamiento de esta.
     * Dado que esto es realizado al momento de soltar el mouse, verificar si se cambio de posicion...
     */
    private void verificarPosicion()
    {
        if( figuraPresionada != null )
        {
            Point p = figuraPresionada.getCentro();
            int nivel = figuraPresionada.getRamo().getNivel() -1;
            String tipo = quitarNumero(figuraPresionada.getRamo().getPeriodo() );
            for( int j = 0 ; j < cursos[nivel].length ; j++ )
            {
                Point p2 = null;
                if( tipo.equals("Anual") )
                    p2 = cursos[nivel][j].getPunto();
                else if( tipo.equals("Semestre") )
                    p2 = cursos[nivel][j].getSemestre( getNumeroString( figuraPresionada.getRamo().getPeriodo() ) -1);
                else if( tipo.equals("Trimestre" ) )
                    p2 = cursos[nivel][j].getTrimestre( getNumeroString( figuraPresionada.getRamo().getPeriodo() ) -1 );
                if( estaDentro( p, p2 ) )
                {
                    //Ademas verificar que la posicion pueda tener al tipo de figura que se le estan incluyendo,,!!
                    if ( tieneFigura(p2) ) // ->Verificar que p2 este vacio. Y si tiene hay que buscarla
                    {//En caso de que posea figura, verificar que sean del mismo tipo para poder intercambiarlas, sino no.
                        //Dado que ambas figuras son del mismo tipo, 
                        for( JFigura f : figures )
                        {
                            String tipo1 = figuraPresionada.getRamo().getPeriodo();
                            String tipo2 = f.getRamo().getPeriodo();
                            if( f != figuraPresionada && f.getX() == p2.getX() && f.getY() == p2.getY() && tipo1.equals(tipo2) )
                            {
                                Point px = posicionFiguraPresionada;
                                f.setX( (int)px.getX() );
                                f.setY( (int)px.getY() );
                                f.setBounds((int)px.getX(), (int)px.getY(), f.getAncho(), f.getAlto());
                                JFigura aux = figuraPresionada;
                                figuraPresionada = f;
                                this.centrarFiguraPresionada();
                                figuraPresionada = aux;
                                posicionFiguraPresionada = p2;
                                break;
                            }
                        }
                    }
                    if( orientacion == vertical )
                    {
                        if( cursos[nivel][j].getPeriodo() != null && cursos[nivel][j].getPeriodo().equals(tipo) )
                        {
                            posicionFiguraPresionada = p2;
                            cursos[nivel][j].setPeriodo(tipo);
                            break;
                        }
                    }
                }
            }
        }
        updateUI();
        repaint();
    }
    
    /**
     * Retorna la posicion en la matriz en la cual se encuentra la figura en cuestion.
     * @param nivelFigura (en la matriz -del la clase llamar como "fPresionada.getRamo().getNivel()-1"-)
     * @param p
     * @return 
     */
    private int getPosicionEnMatriz( int nivelFigura, Point p )
    {
        for( int i = nivelFigura, j=0 ; j < cursos[i].length ; j++ )
        {
            Point p2 = cursos[i][j].getPunto();
            if( p.x == p2.x && p.y == p2.y )
                return j;
        }
        return 0;
    }
    
    /**
     * Verifica si p1 se encuentra dentro de p2. Valido para puntos solamente, tomando como referencia 
     * el alto y ancho de Curso para completar un rectangulo.
     * @param p1
     * @param p2
     * @return p2 esta Dentro de p1
     */
    private boolean estaDentro( Point p1, Point p2 )
    {
        if( p1.getX() >= p2.getX() && p1.getX() <= p2.getX() + Curso.ANCHO &&
            p1.getY() >= p2.getY() && p2.getY() <= p2.getY() + Curso.ALTO )
            return true;
        return false;
    }
    
    public void centrarFiguraPresionada()
    {
        if( figuraPresionada != null )
        {
            //Volver a posicion original de la figuraPresionada.
            this.figuraPresionada.setX( (int)posicionFiguraPresionada.getX() );
            this.figuraPresionada.setY( (int)posicionFiguraPresionada.getY() );
            this.figuraPresionada.setBounds((int)posicionFiguraPresionada.getX(), (int)posicionFiguraPresionada.getY(),
                                    figuraPresionada.getAncho(), figuraPresionada.getAlto());
            //Arreglar posicion de las flechas
            figuraPresionada.setFlechasSalientes(orientacion);
            this.setFlechasEntrantes(this.figuraPresionada.getRamo(), orientacion);
            updateUI();
        }
    }
    
    void cambiarNombreRamo(String nombre, String nombre0) {
        for (JFigura f : this.figures){
            if (f.getNombre().equals(nombre)){
                f.updateUI();
            }
        }
    }

    void setCantidadSemestres(int cantidadSemestres) 
    {
        this.niveles = cantidadSemestres;
        this.matrizCuros();
    }
    
    public JFigura getFigPresionada(){
        return this.figuraPresionada;
    }
    
    @Override
    public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
        if (pageIndex > 0){
            return NO_SUCH_PAGE;
        }
        super.setBackground(Color.white);  // setea el color de fondo blanco del panel de dibujo
        Graphics2D g2 = (Graphics2D) graphics;
        g2.scale(0.5, 0.5);   // redimensiona
        this.quitarSeleccionador();  // oculta el ramo seleccionado
        for (JFigura fig : this.figures){
            fig.resaltarFlechas(false);  // quitar resaltado a la que haya habido
        }
        this.print(graphics);
        return PAGE_EXISTS;
    }

    void resetcolor() {
        super.setBackground(new Color(238,238,238));
    }

    public int getIdentificador() {
        return identificador;
    }

    public void setIdentificador(int identificador) {
        this.identificador = identificador;
    }
    
    
    public void quitarSeleccionador()
    {
        this.seleccionador.setMostrado(false);
    }
    
    public void agregarSeleccionador()
    {
        this.seleccionador.setMostrado(true);
    }

    public int getOrientacion()
    {
        return orientacion;
    }

    public void setOrientacion(int orientacion)
    {
        this.orientacion = orientacion;
    }

    void cambiarCreditoRamo(String nombre, int creditos) {
        for (JFigura fig : this.figures){
            if (fig.getNombre().equals(nombre)){
                fig.getRamo().setCredito(creditos);
            }
        }
        updateUI();
    }

    void actualizacionRamo(Ramo ramo, Ramo ramoModificado) {
        for (JFigura f : this.figures){
            if (f.getNombre().equals(ramo.getNombre())){
                f.setRamo(ramoModificado);
            }
        }
        updateUI();
    }
    
    public int getNiveles(){
        return this.niveles;
    }

    void eliminarJFIgura() {
        if (figuraPresionada != null){
            this.liberarPosicion();
            super.remove(figuraPresionada);
            this.figures.remove(figuraPresionada);
            super.remove(figuraPresionada);
            this.seleccionador.setMostrado(false);
            this.ventana.eliminarRamo(figuraPresionada.getRamo());
            super.updateUI();
        }
    }
    
    public void nombres() {
        for (JFigura f : this.figures){
            f.setTexto();
        }
    }

    public JFigura buscarJFigura(String nombre){
        for (JFigura f : this.figures){
            if (f.getNombre().equals(nombre)){
                return f;
            }
        }
        return null;
    }
    
    public JFigura buscarJFigura(String nombre, int nivel){
        for (JFigura f : this.figures){
            if (f.getNombre().equals(nombre) && f.getNivel() == nivel){
                return f;
            }
        }
        return null;
    }

    public void agregarFlechas(JFigura fig) {
        ArrayList<Ramo> requisitos = fig.getRamo().getPreRequisitos();
        if (requisitos != null){
            for (Ramo r : requisitos){
                if (!this.buscarJFigura(r.getNombre(), r.getNivel()).tieneFlechaA(fig.getRamo())){
                    this.buscarJFigura(r.getNombre(), r.getNivel()).agregarFlecha(fig, this.orientacion);
                    //this.flechas.add(new JFlecha(this.buscarJFigura(r.getNombre()), fig));
                    //fig.agregarFlecha(new JFlecha(this.buscarJFigura(r.getNombre()), fig));
                }
            }
        }
    }

    public void agregarMemoria() {
        Memento memento = new Memento(this.figures);
        this.memoria.addMemento(memento);
        //memoria.imprimir();
        System.out.println("");
    }

    public void deshacer() {
        Memento memento = this.memoria.obtenerAnterior();
        if (memento != null){
            this.figures = memento.obtenerFiguras();
            super.removeAll();
            for (JFigura fig : this.figures){
                //System.out.println("agregada la fig: " + fig.getNombre());
                super.add(fig);
            }
            this.nombres();
            super.repaint();
        }
    }

    void rehacer() {
        Memento memento = this.memoria.obtenerSiguiente();
        if (memento != null){
            this.figures = memento.obtenerFiguras();
            super.removeAll();
            for (JFigura fig : this.figures){
                super.add(fig);
            }
            super.repaint();
        }
    }

    void cambiarOrientacion()
    {
        orientacion = ( orientacion == vertical )? horizontal : vertical;
        this.modificarOrientacionFiguras();
        this.modificarPosicionFlechas(orientacion);
    }
    
    public void setNombreMalla( String nombreMalla )
    {
        this.nombreMalla = nombreMalla;
    }
    
    public String getNombreMalla()
    {
        return this.nombreMalla;
    }

    public ArrayList<JFigura> getFigures() {
        return figures;
    }

    public void setFigures(ArrayList<JFigura> figures) {
        this.figures = figures;
    }

    //Comprobare si funciona seteando que debemos cambiar los x por y
    public void modificarOrientacionFiguras()
    {
        for( JFigura jf : figures )
        {
            int x = jf.getY();
            int y = jf.getX();
            jf.setX(x);
            jf.setY(y);
        }
        rotarMatriz();
        for(JFigura f : figures)
        {
            f.defineTamaño(orientacion);
            f.setBounds( f.getRectangle() );
        }
        super.repaint();
        super.updateUI();
    }
    
    /**
     * Esto comienzo en borde izquierdo, hacia el lado debe saltarse espacioHorizontal
     * Hacia abajo, comienza en bordeSuperior, y baja en espacio vertical + JFigura.alto
     * Bordes iniciales... 75, 75
     * Altura Curso es 100, ancho 200
     * Despues de la altura, existe un espacio que es constanteEnX - del mismo modo hacia el lado
     * es constanteEnY
     */
    public void matrizCuros()
    {
        this.cursos = new Curso[ niveles ][ maxCursos ];
        int xI = bordeIzquierdo;
        int yI = 75;
        for( int i = 0 ; i < this.niveles ; i++ )
        {
            //xI deberá ser el mismo para cada comienzo de iteracion
            xI = bordeIzquierdo;
            for( int j = 0 ; j < maxCursos ; j++ )
            {
                Curso c = new Curso(xI, yI);
                cursos[i][j] = c;
                xI += c.getAncho() + constanteEnX/3;
            }
            yI += 150 + constanteEnY;
        }
    }
    
    /**
     * Rota matriz cursos para 
     */
    private void rotarMatriz()
    {
        for( int i = 0 ; i < cursos.length ; i++ )
        {
            for( int j = 0 ; j < cursos[i].length ; j++ )
            {
                int x = cursos[i][j].getX();
                cursos[i][j].setX( cursos[i][j].getY() );
                cursos[i][j].setY( x );
                cursos[i][j].intercambiarPosiciones();
                int aux = cursos[i][j].getAncho();
                cursos[i][j].setAncho( cursos[i][j].getAlto() );
                cursos[i][j].setAlto( aux );
            }
        }
    }
    
    /**
     * 
     * @param malla recibe la malla con los ramos a cargar.
     */
    public void cargarCursos(Malla malla){
        for(int i = 1; i <= malla.getDuracion();i++){//Ciclo que recorre los años de duración de la carrera.
            if (malla.getRamos().containsKey(i)){//Verificamos si existe un año con algun curso ya inscrito.
                for(Ramo ramo:malla.getRamosNivel(i)){//Recorre todas los ramos para el año correspondiente.
                    JFigura figura = new JFigura(ramo.getPosicionX(), ramo.getPosicionY(), malla.getNombre(), ramo, orientacion);//Creamos la figura
                    this.addFigure(figura);//La agregamos al ArrayList.
                    this.posicionCargada( figura );
                    super.add(figura);//La agregamos gráficamente.
                }
                super.repaint();//Repintamos
            }
        }
    }
    
    
    public void cargarFlechas(ArrayList<Flecha> flechas){
        if(flechas.size() > 0){
            for(Flecha flecha:flechas){
                for(JFigura figura:figures){
                    if(flecha.getPartida().getNombre().equals(figura.getNombre())) {   
                        figura.cargarFlecha(flecha);
                        figura.updateUI();
                        super.updateUI();
                    }
                }
            }
        }
    }

    public int getNumeroString( String s )
    {
        if( s.equals("Anual") )
            return 0;
        String numero = "";
        int largo=s.length();
        for(int i=0; i <largo ; i++)
        { 
            if (Character.isDigit(s.charAt(i))) 
                numero = numero + s.charAt(i);
        } 
        try{
            return Integer.parseInt( numero );
        }
        catch( NumberFormatException e )
        {
            System.out.println(e);
        }
        return 0;
    }
    
    public String quitarNumero( String s )
    {
        String st = "";
        int largo = s.length();
        for(int i=0; i <largo ; i++)
        { 
            if ( !Character.isDigit( s.charAt(i) ) ) 
                st = st + s.charAt(i);
        }
        return st.trim();
    }

    private void revisarFlechas() {
        for (JFigura f : figures){
            f.revisarFlechasRepetidas();
        }
        for (JFigura f  : figures){
            f.clear();
        }
        
        for (JFigura fig1 : figures){
            ArrayList<Flecha> flechas1 = fig1.getFlechas();
            for (JFigura fig2 : figures){
                ArrayList<Flecha> flechas2 = fig2.getFlechas();
                for (Flecha flecha1 : flechas1){
                    for (Flecha flecha2 : flechas2){
                        flecha1.interseccionFlecha(flecha2);
                    }
                }
            }
        }
        for (JFigura figura : figures){
            ArrayList<Flecha> flechas = figura.getFlechas();
            Flecha aux = null;
            for (Flecha f  : flechas){
                if (buscarJFigura(f.llegada().nombre, f.llegada().nivel) == null){
                    aux = f;
                }
            }
            figura.eliminarFlecha(aux);
        }
    }

       /**
     * Dado un punto, retorna la flecha que lo contiene
     */
    private Flecha buscarFlecha(Point point) {
        for (JFigura fig : figures){
            if (fig.contieneFlecha(point) != null){
                return fig.contieneFlecha(point);
            }
        }
        return null;
    }
    
    private JFigura buscarJFigura(Flecha flechaPresionada) {
        if (flechaPresionada.seleccionado1  == flechaPresionada.cantidadPuntos()-2){ // ultimo tramo
            Ramo ramo = flechaPresionada.llegada();
            return this.buscarJFigura(ramo.getNombre(), ramo.getNivel());
        }
        
        if (flechaPresionada.seleccionado1 == 0){
            for (JFigura fig : figures){
                if (fig.contieneFlecha(flechaPresionada)){
                    return fig;
                }
            }
        }
        return null;
    }
    
    /**
     * Dado un punto retorna un string que representa al elemento clickeado
     */
    private String buscarElementoClickeado(Point point) {
        for (JFigura fig : figures){
            if (fig.inside(point)){
                return "figura";
            }
            else if (fig.dentroFlecha(point) != null){
                return "flecha";
            }
        }
        return "espacio vacio";
    }
    
    private void traerFiguraAlFrente(JFigura fig) {
        Component[] components = super.getComponents(); //array con todos los componentes insertados
        super.removeAll();
        super.add(fig);
        for (int i=0; i< components.length; i++){
            if (components[i] != fig){
                super.add(components[i]);
            }                
        }
    }

        /**
     * retorna la flecha que llega a un ramo 
     */
    private Flecha buscarFlecha(Ramo ramo) {
        for (JFigura figura : figures){
            ArrayList<Flecha> flechasSalientes = figura.getFlechas();
            for (Flecha flecha : flechasSalientes){
                if (flecha.llegada().equals(ramo)){
                    return flecha;
                }
            }
        }
        return null;
    }
    
        /**
     * Setea las posiciones de las flechas que entran a la figura
     */
    private void setFlechasEntrantes(Ramo ramo, int orientacion) {
        ArrayList<Ramo> requisitos = ramo.getPreRequisitos();
        for (Ramo r : requisitos) {
            JFigura fig = this.buscarJFigura(r.getNombre(), r.getNivel());
            fig.setFinalFlecha(figuraPresionada.getLocation(), ramo, orientacion);
        }
    }
  
     /**
     * Al cambiar la orientacion del panel, cambia la posicion de las flechas
     */
    private void modificarPosicionFlechas(int orientacion) {
//        for (JFigura fig : figures){
//            fig.modificarPosicionFlechas(orientacion);
//        }
        //this.eliminarFlechas();
        //this.rehacerFlechas(orientacion);
        for (JFigura fig : figures){
            fig.rotarFlechas();
        }
    }
    
    public void agregarTramo() {
        this.flechaPresionada.agregarTramo();
    }

    private void posicionCargada(JFigura figura)
    {
        Point p = figura.getPunto();
        String tipo = figura.getRamo().getPeriodo();
        if( tipo.equals( "Anual" ) )
        {
            //Buscar y definir posicion
            for( int i = 0 ; i < cursos.length ; i++ )
            {
                for( int j = 0 ; j < cursos[i].length ; j++ )
                {
                    Point punto = cursos[i][j].getPunto();
                    if( punto.getX() == p.getX() && punto.getY() == p.getY() )
                        cursos[i][j].setPeriodo(tipo);
                }
            }
        }
        int n = getNumeroString(tipo);
        tipo = quitarNumero(tipo);
        //Buscar y definir posicion
        if( tipo.equals("Semestre") )
        {
            for( int i = 0 ; i < cursos.length ; i++ )
            {
                for( int j = 0 ; j < cursos[i].length ; j++ )
                {
                    Point punto = cursos[i][j].getSemestre(n-1);
                    if( punto.getX() == p.getX() && punto.getY() == p.getY() )
                        cursos[i][j].setPeriodo(tipo);
                }
            }
        }
        else if( tipo.equals("Trimestre") )
        {
            for( int i = 0 ; i < cursos.length ; i++ )
            {
                for( int j = 0 ; j < cursos[i].length ; j++ )
                {
                    Point punto = cursos[i][j].getTrimestre(n-1);
                    if( punto.getX() == p.getX() && punto.getY() == p.getY() )
                        cursos[i][j].setPeriodo(tipo);
                }
            }
        }
    }

    public ArrayList<Flecha> getFlechas() {
        ArrayList<Flecha> respuesta = new ArrayList<>();
        for (JFigura figura : this.figures){
            ArrayList<Flecha> flechasFigura = figura.getFlechas();
            for (Flecha f  : flechasFigura){
                respuesta.add(f);
            }
        }
        return respuesta;
    }
    
    public void marcaCursos( Graphics2D g )
    {
        for( int i = 0 ; i < cursos.length ; i++ )
            for( int j = 0 ; j < cursos[i].length ; j++ )
                g.drawRect(cursos[i][j].getX(), cursos[i][j].getY(), cursos[i][j].getAncho(), cursos[i][j].getAlto() );
    }

    private void eliminarFlechas() {
        for (JFigura fig : this.figures){
            fig.eliminarFlechas();
        }
    }

    private void rehacerFlechas(int orientacion) {
//        switch(orientacion){
//            case JPanelDibujo.horizontal:
                for (JFigura fig : figures){
                    if (fig.getRamo().cantPreRequisitos() > 0){
                        this.agregarFlechas(fig);
                    }
                }
//                break;
//            case JPanelDibujo.vertical:
//                break;
//        }
    }

    private void resaltarFlechas(JFigura figuraPresionada) {
        for (JFigura fig : this.figures){
            fig.resaltarFlechas(false);  // quitar resaltado a la que haya habido
        }
        if (figuraPresionada != null){
            figuraPresionada.resaltarFlechas(true); // resaltar flechas de la fig presionada
        }
        super.repaint();
    }

    private void imprimirInfo(JFigura figuraPresionada) {
        if (figuraPresionada != null){
            System.out.println("la figura tiene " + figuraPresionada.getFlechas().size() + "flechas");
            System.out.print("figura " + figuraPresionada.getRamo().nombre + " tiene como prerequisitos: ");
            for (Ramo r : figuraPresionada.getRamo().ramosRequisitos){
                System.out.print("- " + r.nombre + "("+r.creditos+") ");
            }
            System.out.println("");
        }
    }

    private void imprimirInfo(Flecha flechaPresionada) {
        if (flechaPresionada != null)
            System.out.println("flecha desde " + flechaPresionada.getPartida().nombre + " hasta " + flechaPresionada.llegada().nombre);
    }
    
        /**
     * Elimina las flechas que llegan a cierto ramo 
     */
    public void eliminarFlechasAntiguas(Ramo ramo) {
        System.out.println("eliminar flechas que llegan al ramo " + ramo.nombre);
        ArrayList<JFigura> figsaux = new ArrayList<>();
        for (JFigura fig : this.figures){
            for (Flecha f : fig.flechas){
                if (f.llegada().equals(ramo)){
                    figsaux.add(fig);
                }
            }
        }
        for (JFigura fig : figsaux){
            fig.eliminarFlecha(ramo);
        }
    }

}
